#ifndef __GPIO_H_
#define __GPIO_H_

// clang-format off

enum gpio_pin {
    PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PA8, PA9, PA10, PA11, PA12, PA13, PA14, PA15,
    PB0, PB1, PB2, PB3, PB4, PB5, PB6, PB7, PB8, PB9, PB10, PB11, PB12, PB13, PB14, PB15,
    PC0, PC1, PC2, PC3, PC4, PC5, PC6, PC7, PC8, PC9, PC10, PC11, PC12, PC13, PC14, PC15,
    PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7, PD8, PD9, PD10, PD11, PD12, PD13, PD14, PD15,
    PE0, PE1, PE2, PE3, PE4, PE5, PE6, PE7, PE8, PE9, PE10, PE11, PE12, PE13, PE14, PE15,
    PF0, PF1, PF2, PF3, PF4, PF5, PF6, PF7, PF8, PF9, PF10, PF11, PF12, PF13, PF14, PF15,
    PG0, PG1, PG2, PG3, PG4, PG5, PG6, PG7, PG8, PG9, PG10, PG11, PG12, PG13, PG14, PG15,
    PH0, PH1, PH2, PH3, PH4, PH5, PH6, PH7, PH8, PH9, PH10, PH11, PH12, PH13, PH14, PH15,
    PI0, PI1, PI2, PI3, PI4, PI5, PI6, PI7, PI8, PI9, PI10, PI11, PI12, PI13, PI14, PI15
};

/* gpio_nvic_ex_config专用宏定义 */
#define GPIO_FTIR           1       /* 下降沿触发 */
#define GPIO_RTIR           2       /* 上升沿触发 */
#define GPIO_BTIR           3       /* 任意边沿触发 */

/* GPIO设置专用宏定义 */
#define GPIO_MODE_IN        0       /* 普通输入模式 */
#define GPIO_MODE_OUT       1       /* 普通输出模式 */
#define GPIO_MODE_AF        2       /* AF功能模式 */
#define GPIO_MODE_AIN       3       /* 模拟输入模式 */

#define GPIO_SPEED_LOW          0       /* GPIO速度(低速,2M) */
#define GPIO_SPEED_MID          1       /* GPIO速度(中速,10M) */
#define GPIO_SPEED_HIGH         2       /* GPIO速度(高速,50M) */
#define GPIO_SPEED_VERY_HIGH    3       /* GPIO速度(高速,100M) */

#define GPIO_PUPD_NONE      0       /* 不带上下拉 */
#define GPIO_PUPD_PU        1       /* 上拉 */
#define GPIO_PUPD_PD        2       /* 下拉 */

#define GPIO_OTYPE_PP       0       /* 推挽输出 */
#define GPIO_OTYPE_OD       1       /* 开漏输出 */

/* GPIO引脚位置宏定义  */
#define GPIO_PIN_0           1<<0
#define GPIO_PIN_1           1<<1
#define GPIO_PIN_2           1<<2
#define GPIO_PIN_3           1<<3
#define GPIO_PIN_4           1<<4
#define GPIO_PIN_5           1<<5
#define GPIO_PIN_6           1<<6
#define GPIO_PIN_7           1<<7
#define GPIO_PIN_8           1<<8
#define GPIO_PIN_9           1<<9
#define GPIO_PIN_10          1<<10
#define GPIO_PIN_11          1<<11
#define GPIO_PIN_12          1<<12
#define GPIO_PIN_13          1<<13
#define GPIO_PIN_14          1<<14
#define GPIO_PIN_15          1<<15

// clang-format on

/**
 * @brief       外部中断配置函数, 只针对GPIOA~GPIOI
 * @note        该函数会自动开启对应中断, 以及屏蔽线
 * @param       pinx:PA0~PI15, GPIO引脚位置
 * @param       tmode: 1~3, 触发模式
 *   @arg       GPIO_FTIR, 1, 下降沿触发
 *   @arg       GPIO_RTIR, 2, 上升沿触发
 *   @arg       GPIO_BTIR, 3, 任意电平触发
 * @param       callback: 外部中断回调函数, 当GPIO引脚发生中断时会调用此函数
 * @retval      无
 */
void gpio_nvic_ex_config(uint8_t pinx, uint8_t tmode, void (*callback)(void));

/**
 * @brief       GPIO外部中断回调函数注册
 * @param       pinx:PA0~PI15, GPIO引脚位置
 * @param       callback: 回调函数指针, 当GPIO引脚发生中断时会调用此函数
 * @retval      无
 */
void gpio_ex_callback_register(uint8_t pinx, void (*callback)(void));

/**
 * @brief       GPIO外部中断回调函数注销
 * @param       pinx:PA0~PI15, GPIO引脚位置
 * @retval      无
 */
void gpio_ex_callback_deregister(uint8_t pinx);

/**
 * @brief       GPIO复用功能选择设置
 * @param       gpio_map[pinx].port: GPIOA~GPIOI, GPIO指针
 * @param       pinx: 0X0000~0XFFFF, 引脚位置, 每个位代表一个IO, 第0位代表Px0, 第1位代表Px1, 依次类推. 比如0X0101, 代表同时设置Px0和Px8.
 *   @arg       SYS_GPIO_PIN0~SYS_GPIO_PIN15, 1<<0 ~ 1<<15
 * @param       afx:0~15, 代表AF0~AF15.
 *              AF0~15设置情况(这里仅是列出常用的, 详细的请见STM32F407xx数据手册, Table 7):
 *   @arg       AF0:MCO/SWD/SWCLK/RTC       AF1:TIM1/TIM2               AF2:TIM3~5                  AF3:TIM8~11
 *   @arg       AF4:I2C1~I2C3               AF5:SPI1/SPI2/I2S2          AF6:SPI3/I2S3               AF7:USART1~3
 *   @arg       AF8:USART4~6                AF9;CAN1/CAN2/TIM12~14      AF10:USB_OTG/USB_HS         AF11:ETH
 *   @arg       AF12:FSMC/SDIO/OTG_FS       AF13:DCIM                   AF14:                       AF15:EVENTOUT
 * @retval      无
 */
void gpio_af_set(uint8_t pinx, uint8_t afx);

/**
 * @brief       GPIO通用设置
 * @param       pinx:PA0~PG15, GPIO引脚位置
 *
 * @param       mode: 0~3; 模式选择, 设置如下:
 *   @arg       SYS_GPIO_MODE_IN,  0, 输入模式(系统复位默认状态)
 *   @arg       SYS_GPIO_MODE_OUT, 1, 输出模式
 *   @arg       SYS_GPIO_MODE_AF,  2, 复用功能模式
 *   @arg       SYS_GPIO_MODE_AIN, 3, 模拟输入模式
 *
 * @param       otype: 0 / 1; 输出类型选择, 设置如下:
 *   @arg       SYS_GPIO_OTYPE_PP, 0, 推挽输出
 *   @arg       SYS_GPIO_OTYPE_OD, 1, 开漏输出
 *
 * @param       ospeed: 0~2; 输出速度, 设置如下(注意: 不能为0!!):
 *   @arg       SYS_GPIO_SPEED_LOW,  2, 低速
 *   @arg       SYS_GPIO_SPEED_MID,  1, 中速
 *   @arg       SYS_GPIO_SPEED_HIGH, 3, 高速
 *
 * @param       pupd: 0~3: 上下拉设置, 设置如下:
 *   @arg       SYS_GPIO_PUPD_NONE, 0, 不带上下拉
 *   @arg       SYS_GPIO_PUPD_PU,   1, 上拉
 *   @arg       SYS_GPIO_PUPD_PD,   2, 下拉
 *   @arg       SYS_GPIO_PUPD_RES,  3, 保留
 *
 * @note:       注意:
 *              1, 在输入模式(普通输入/模拟输入)下, otype 和 ospeed 参数无效!!
 *              2, 在输出模式下, pupd 参数无效!!(开漏输出无法使用内部上拉电阻!!)
 * @retval      无
 */
void gpio_pin_init(uint8_t pinx, uint32_t mode, uint32_t otype, uint32_t ospeed, uint32_t pupd);

/**
 * @brief       设置GPIO某个引脚的输出状态
 * @param        pinx:PA0~PG15, GPIO引脚位置
 * @param       status: 0/1, 引脚状态(仅最低位有效), 设置如下:
 *   @arg       0, 输出低电平
 *   @arg       1, 输出高电平
 * @retval      无
 */
void gpio_write_pin(uint8_t pinx, uint8_t status);

/**
 * @brief       读取GPIO某个引脚的状态
 * @param        pinx:PA0~PG15, GPIO引脚位置
 * @retval      返回引脚状态, 0, 低电平; 1, 高电平
 */
uint8_t gpio_read_pin(uint8_t pinx);

/**
 * @brief       切换GPIO某个引脚的状态
 * @param        pinx:PA0~PG15, GPIO引脚位置
 * @retval      无
 */
void gpio_toggle_pin(uint8_t pinx);

#endif /* __GPIO_H_ */
